package gates;

import register.Register;
import gates.FunctionGate;
import mathtools.Complex;
/**
 * Functional representation of a iI gate.
 * This implements Gate interface, so consult this for public methods.
 * The constructor for this gate is protected, so generating such an object is left
 * for the factory class <code>Factory</code>
 * @author Jan Zaucha
 */
public class ComplexIdentityFunction extends FunctionGate {

	/** Store the target qubit the gate acts on*/	
	private int target;

	/**
	 * Protected constructor for a functional representation of a iI gate
	 * Requires a target bit for the gate to operate on, however if the target bit is
	 * -1 the gate will act on all qubits
	 * @param target the target bit to hadamard transform (counting qubits from 0)
	 */
	protected ComplexIdentityFunction(int target){
		this.target = target; // actually the only special case is when target = -1
	}

	/**
	 * Returns the name of the gate regardless of representation.
	 */
	public String getName() {
		return "Complex Identity";
	}

	/**
	 * Applies this gate to the given register. See interface <code>Gate</code> for usage.
	 * @param r the register 
	 */
	public void apply(Register r) {
		if (target >= r.getNumQbits() || target < -1){
			throw new IllegalArgumentException("Target qubit not in register. Register size (qubits): " + r.getNumQbits() + " Target qubit: " + target);
		}
		// if target is flagged "-1" we hadamard transform all qubits
		if(target==-1){
			for(int j=0; j< r.getNumQbits(); j++){
				this.applyToSingleQubit(r);
			}
		}
		// else apply to a given single qubit
		else {
			this.applyToSingleQubit(r);
		}
	}

	/**
	 * Private method that applies iI gate to the given register given the target qubit. 
	 * @param r the register 
	 */
	private void applyToSingleQubit(Register r){
		int numStates = r.getHeight();    // number of states in register
		Complex newAmplitude;
		for(int j=0; j< numStates; j++){
			newAmplitude =  Complex.multiplyComplex(new Complex(0.0f, 1.0f), r.getElement(0, j));
			r.setElement(0, j, newAmplitude);
			
		}
		// normalize register
		r.normalise();

	}

}
